//
//  LanBCrashReport.m
//  AFNetworking
//
//  Created by v on 2020/12/12.
//

#import "LanBCrashReport.h"
#import <KSCrash/KSCrash.h>
#import <KSCrash/KSCrashInstallationStandard.h>
#import <KSCrash/KSCrashReportFilterAppleFmt.h>

#import "skpsmtpmessage/SMTPLibrary/SKPSMTPMessage.h"
#import "skpsmtpmessage/SMTPLibrary/NSData+Base64Additions.h"

@interface LanBCrashReport () <SKPSMTPMessageDelegate>

@property (nonatomic, strong) NSString *email;
/** SMTP服务器 地址 */
@property (nonatomic, strong) NSString *relayHost;
/** 发送 email 密码或者 smtp授权密码 */
@property (nonatomic, strong) NSString *password;
@property (nonatomic, strong) NSDictionary<NSString*,NSString*> *infos;

@property (nonatomic, strong) NSMutableDictionary *dicReports;
@property (nonatomic, strong) NSMutableDictionary *dicMegs;

@end

@implementation LanBCrashReport

/** 返回单例  */
static LanBCrashReport *shareInstance;
+ (instancetype)shared
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (!shareInstance) {
            shareInstance = [[self alloc] init];
        }
    });
    return shareInstance;
}

- (void)lanb_install
{
    [self lanb_installWithEmailReporter:nil relayHost:nil password:nil];
}

- (void)lanb_installWithEmailReporter:(NSString *)email relayHost:(nonnull NSString *)relayHost password:(nonnull NSString *)password
{
    self.email     = email;
    self.relayHost = relayHost;
    self.password  = password;
    
    // 3s后 初始化 crash 收集, 防止其它服务 未传导调用 NSSetUncaughtExceptionHandler
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // 初始化 crash 收集
        KSCrashInstallationStandard* installation = [KSCrashInstallationStandard sharedInstance];
        [installation install];
        // 设置日志存贮规则
        KSCrash.sharedInstance.deleteBehaviorAfterSendAll = KSCDeleteNever;
        // 设置自定义 crash 处理
        installation.onCrash = LanBCrashReport_crashCallback;
        
        // 上报已有crash
        [self reportCrashs];
    });
}

/** ！！！方法中不能使用OC 代码 */
static void LanBCrashReport_crashCallback(const KSCrashReportWriter* writer)
{

}

- (void)lanb_configCustomInfos:(NSDictionary<NSString *,NSString *> *)infos
{
    self.infos = infos;
}

- (void)reportCrashs
{
    // 没有配置 上报 email 信息
    if (self.email.length == 0 || self.relayHost.length == 0 || self.password.length == 0) {
        return;
    }
    
    // 查询 本地 crash 信息
    self.dicReports = NSMutableDictionary.new;
    self.dicMegs    = NSMutableDictionary.new;
    
    __weak typeof(self) weakSelf = self;
    [KSCrash.sharedInstance.reportIDs enumerateObjectsUsingBlock:^(NSNumber*  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        NSDictionary *dicReport = [KSCrash.sharedInstance reportWithID:obj];
        if (dicReport)
            strongSelf.dicReports[obj] = dicReport;
    }];
    
    __block NSMutableDictionary *dicReportsTemp = NSMutableDictionary.new;
    [self.dicReports enumerateKeysAndObjectsUsingBlock:^(NSNumber*  _Nonnull key, NSDictionary*  _Nonnull obj, BOOL * _Nonnull stop) {
        id filter = [KSCrashReportFilterAppleFmt filterWithReportStyle:KSAppleReportStyleSymbolicatedSideBySide];
        [filter filterReports:@[obj] onCompletion:^(NSArray *filteredReports, BOOL completed, NSError *error) {
            if (completed && !error && filteredReports.count >0) {
                dicReportsTemp[key] = filteredReports[0];
            }
        }];
    }];
    self.dicReports = dicReportsTemp;
    
    // 发送 crash 日志
    [self _sendReports];
}

- (void)_sendReports
{
    if (self.dicReports.count == 0) {
        return;
    }
    __weak typeof(self) weakSelf = self;
    [self.dicReports enumerateKeysAndObjectsUsingBlock:^(NSNumber*  _Nonnull key, NSString*  _Nonnull obj, BOOL * _Nonnull stop) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        [strongSelf _sendEmail:key content:obj];
    }];
}

- (void)_sendEmail:(NSNumber*)reportID content:(NSString*)content
{
    SKPSMTPMessage *myMessage = [[SKPSMTPMessage alloc] init];
    myMessage.delegate        = self;
    
    myMessage.fromEmail    = self.email;
    myMessage.toEmail      = self.email;
    myMessage.relayHost    = self.relayHost;
    myMessage.requiresAuth = YES;
    myMessage.wantsSecure  = YES;
    if (myMessage.requiresAuth) {
        myMessage.login = self.email;   //发送者邮箱的用户名
        myMessage.pass = self.password; //发送者邮箱的 授权密码
    }

//    NSDate *now = [NSDate.date dateByAddingTimeInterval:[NSTimeZone.systemTimeZone secondsFromGMTForDate:NSDate.date]];
    myMessage.subject = [NSString stringWithFormat:@"iOS crash _ device name( %@ )",  UIDevice.currentDevice.name];//邮件主题

    __block NSString *target = content;
    if (self.infos.count > 0) {
        target = @"====== infos start ======\n";
        [self.infos enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
            target = [target stringByAppendingString:[NSString stringWithFormat:@"%@ : %@\n", key, obj]];
        }];
        target = [target stringByAppendingString:@"====== infos   end ======\n\n\n"];
        target = [target stringByAppendingString:content];
    }
    
    /* >>>>>>>>>>>>>>>>>>>> *   设置邮件内容   * <<<<<<<<<<<<<<<<<<<< */
    NSDictionary *plainPart = [NSDictionary dictionaryWithObjectsAndKeys:
                               @"text/plain; charset=UTF-8",kSKPSMTPPartContentTypeKey,
                               target,kSKPSMTPPartMessageKey,
                               @"8bit",kSKPSMTPPartContentTransferEncodingKey,nil];

    myMessage.parts = [NSArray arrayWithObjects:plainPart,nil];
    self.dicMegs[reportID] = myMessage;
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [myMessage send];
        [[NSRunLoop currentRunLoop] run];
    });
}

#pragma mark - SKPSMTPMessageDelegate
-(void)messageSent:(SKPSMTPMessage *)message
{
    __block NSNumber *reportID;
    [self.dicMegs enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        if (message == obj) {
            reportID = key;
            *stop = YES;
        }
    }];
    if (reportID) {
        message.delegate = nil;
        [self.dicMegs removeObjectForKey:reportID];
        [KSCrash.sharedInstance deleteReportWithID:reportID];
    }
}

-(void)messageFailed:(SKPSMTPMessage *)message error:(NSError *)error
{
    __block NSNumber *reportID;
    [self.dicMegs enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        if (message == obj) {
            reportID = key;
            *stop = YES;
        }
    }];
    if (reportID) {
        message.delegate = nil;
        [self.dicMegs removeObjectForKey:reportID];
    }
}

@end
